<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>The GDI</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Winapi, Windows API, C, no MFC, GDI">
<meta name="description" content="In this part of the Winapi tutorial,
we present the Graphics Device interface.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">

<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>The GDI</h1>


<p>
The GDI (Graphics Device Interface) is an interface for working with graphics.
It is used to interact with graphic devices such as monitors, printers or files.
The GDI allows programmers to display data on a screen or printer without
having to be concerned about the details of a particular device.
The GDI insulates the programmer from the hardware. From the programmer's
point of view, the GDI is a group of API functions for working with graphics. 
The GDI consists of 2D Vector Graphics, Fonts and Images. To begin
drawing graphics, we must obtain a device context (DC) object.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<h2>Pixels</h2>

<p>
The <code>SetPixel()</code> is a function that draws a single pixel
on the window. 
</p>


<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawPixels(HWND hwnd);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Pixels";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Pixels",
              WS_OVERLAPPEDWINDOW | WS_VISIBLE,
              100, 100, 250, 150, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_PAINT:

      DrawPixels(hwnd);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void DrawPixels(HWND hwnd)
{
  PAINTSTRUCT ps;
  RECT r;

  HDC hdc = BeginPaint(hwnd, &amp;ps);

  GetClientRect(hwnd, &amp;r);

  for (int i=0; i<1000; i++) 
  {
    int x = (rand() % r.right - r.left);
    int y = (rand() % r.bottom - r.top);
    SetPixel(hdc, x, y, RGB(255, 0, 0));
  }

  EndPaint(hwnd, &amp;ps);
}
</pre>

<p>
In our example we display randomly 1000 red pixels on the client area of
a window. 
</p>

<pre class="explanation">
wc.style = CS_HREDRAW | CS_VREDRAW;
</pre>

<p>
These two flags cause the window to be redrawn when it is resized.
</p>

<pre class="explanation">
case WM_PAINT:

  DrawPixels(hwnd);
  break;
</pre>

<p>
Drawing is performed in a reaction to the <code>WM_PAINT</code> message.
The actual drawing is delegated to the <code>DrawPixels()</code> method.
</p>

<pre class="explanation">
HDC hdc = BeginPaint(hwnd, &amp;ps);
</pre>

<p>
The <code>BeginPaint()</code> function prepares the specified window for 
painting. It fills a <code>PAINTSTRUCT</code> structure with information about 
the painting. It returns a handle to a display device context for the specified 
window.
</p>

<pre class="explanation">
GetClientRect(hwnd, &r);
</pre>

<p>
We retrieve the the coordinates of a window's client area. We will randomly
draw on a window and we need to know, where we can draw at the moment.
</p>

<pre class="explanation">
for (int i = 0; i<1000; i++) 
{
  int x = (rand() % r.right - r.left);
  int y = (rand() % r.bottom - r.top);
  SetPixel(hdc, x, y, RGB(255, 0, 0));
}
</pre>

<p>
1000 points are randomly drawn on the window. The <code>SetPixel()</code> 
function draws a pixel at a specified location using a chosen colour. 
</p>

<pre class="explanation">
EndPaint(hwnd, &amp;ps);
</pre>

<p>
At the end of the painting we call the <code>EndPaint()</code> functions.
The function releases the display device context that <code>BeginPaint()</code> 
retrieved.
</p>


<img src="/img/gui/winapi/pixels.png" alt="Pixels">
<div class="figure">Figure: Pixels</div>


<h2>Rectangle</h2>

<p>
To draw a rectangle, we use the <code>Rectangle()</code> function.
</p>

<pre>
BOOL Rectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, 
    int nBottomRect);
</pre>

<p>
The first parameter of the function is the handle to the device context. 
The next two parameters are the x, y coordinates of the upper-left corner
of the rectangle. The last two parameters are the x, y coordinates of the
lower-right corner of the rectangle. If the function fails, the return value 
is zero. If it succeeds, the return value is non-zero.
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Rectangle";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Rectangle",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 250, 200, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;

  switch(msg)
  {
    case WM_PAINT:

      hdc = BeginPaint(hwnd, &amp;ps);
      Rectangle(hdc, 50, 50, 200, 100);
      EndPaint(hwnd, &amp;ps);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}
</pre>

<p>
The outline of the rectangle is drawn using the current pen.
The background is drawn using the current brush.
</p>

<pre class="explanation">
Rectangle(hdc, 50, 50, 200, 100);
</pre>

<p>
The rectangle is drawn using the <code>Rectangle()</code> function.
We draw the rectangle using two points. Top left point and bottom right point.
</p>

<img src="/img/gui/winapi/rectangle.png" alt="Rectangle">
<div class="figure">Figure: Rectangle</div>


<h2>Pen</h2>

<p>
Pen is an elementary graphics object. It is used to draw lines,
curves and outlines of rectangles, ellipses, polygons or other shapes.
</p>

<p>
The <code>CreatePen()</code> function creates a logical pen with a specified
style, width and colour.
</p>


<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawLines(HWND);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Pens";
  wc.hInstance     = hInstance;
  wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Pens",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 250, 180, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_PAINT:

      DrawLines(hwnd);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void DrawLines(HWND hwnd) 
{
  PAINTSTRUCT ps;

  HDC hdc = BeginPaint(hwnd, &amp;ps);
  HPEN hPen1 = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
  HPEN hPen2 = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
  HPEN hPen3 = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
  HPEN hPen4 = CreatePen(PS_DASHDOT, 1, RGB(0, 0, 0));
  HPEN hPen5 = CreatePen(PS_DASHDOTDOT, 1, RGB(0, 0, 0));

  HPEN holdPen = SelectObject(hdc, hPen1);
  MoveToEx(hdc, 50, 30, NULL);
  LineTo(hdc, 200, 30);

  SelectObject(hdc, hPen2);
  MoveToEx(hdc, 50, 50, NULL);
  LineTo(hdc, 200, 50);

  SelectObject(hdc, hPen2);
  MoveToEx(hdc, 50, 70, NULL);
  LineTo(hdc, 200, 70);

  SelectObject(hdc, hPen3);
  MoveToEx(hdc, 50, 90, NULL);
  LineTo(hdc, 200, 90);

  SelectObject(hdc, hPen4);
  MoveToEx(hdc, 50, 110, NULL);
  LineTo(hdc, 200, 110);

  SelectObject(hdc, holdPen);
  DeleteObject(hPen1);
  DeleteObject(hPen2);
  DeleteObject(hPen3);
  DeleteObject(hPen4);
  DeleteObject(hPen5);

  EndPaint(hwnd, &amp;ps);  
}
</pre>

<p>
In our example, we draw 5 different lines. Using 5 different pen styles.
</p>

<pre class="explanation">
case WM_PAINT:

  DrawLines(hwnd);
  break;
</pre>

<p>
The actual drawing is delegated to the <code>DrawLines()</code> method.
</p>

<pre class="explanation">
HPEN hPen1 = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
</pre>

<p>
The <code>CreatePen()</code> function creates a logical pen with a specified
style, width and colour. The <code>PS_SOLID</code> stands for a solid pen.
We use the <code>RGB</code> macro to generate a colour for the pen.  
</p>

<pre class="explanation">
SelectObject(hdc, hPen1);
</pre>

<p>
To activate a pen, we call the <code>SelectObject()</code> function.
</p>

<pre class="explanation">
MoveToEx(hdc, 50, 30, NULL);
LineTo(hdc, 200, 30);
</pre>

<p>
To draw lines, we use the <code>MoveToEx()</code> and the <code>LineTo()</code>
functions.
</p>

<pre class="explanation">
DeleteObject(hPen1);
DeleteObject(hPen2);
DeleteObject(hPen3);
DeleteObject(hPen4);
DeleteObject(hPen5);
</pre>

<p>
In the end, we clean up resources.
</p>

<img src="/img/gui/winapi/lines.png" alt="Lines">
<div class="figure">Figure: Lines</div>


<h2>Brush</h2>

<p>
A Brush is an elementary graphics object. It is used to paint the
background of graphics shapes, such as rectangles, ellipses or polygons.
A brush can be a solid colour a hatch or a custom bitmap pattern.
</p>


<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawRectangles(HWND);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Brush";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Solid Brush",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 220, 240, NULL, NULL, hInstance, NULL);

  while (GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_PAINT:

      DrawRectangles(hwnd);	    
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void DrawRectangles(HWND hwnd)
{
  PAINTSTRUCT ps;

  HDC hdc = BeginPaint(hwnd, &amp;ps);
  HPEN hPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
  HPEN holdPen = SelectObject(hdc, hPen);

  HBRUSH hBrush1 = CreateSolidBrush(RGB(121, 90, 0));
  HBRUSH hBrush2 = CreateSolidBrush(RGB(240, 63, 19));
  HBRUSH hBrush3 = CreateSolidBrush(RGB(240, 210, 18));
  HBRUSH hBrush4 = CreateSolidBrush(RGB(9, 189, 21));

  HBRUSH holdBrush = SelectObject(hdc, hBrush1);

  Rectangle(hdc, 30, 30, 100, 100);
  SelectObject(hdc, hBrush2);
  Rectangle(hdc, 110, 30, 180, 100);
  SelectObject(hdc, hBrush3);
  Rectangle(hdc, 30, 110, 100, 180);
  SelectObject(hdc, hBrush4);
  Rectangle(hdc, 110, 110, 180, 180);

  SelectObject(hdc, holdPen);
  SelectObject(hdc, holdBrush);

  DeleteObject(hPen);
  DeleteObject(hBrush1);
  DeleteObject(hBrush2);
  DeleteObject(hBrush3);
  DeleteObject(hBrush4);

  EndPaint(hwnd, &amp;ps);
}
</pre>

<p>
In the following example, we create 4 rectangles filled with 4 different
solid colours.
</p>

<pre class="explanation">
HBRUSH hBrush1 = CreateSolidBrush(RGB(121, 90, 0));
</pre>

<p>
Here we create a solid colour brush.
</p>

<pre class="explanation">
HBRUSH holdBrush = SelectObject(hdc, hBrush1);
</pre>

<p>
A new brush is selected into the device context.
</p>

<img src="/img/gui/winapi/solidbrush.png" alt="Solid brush">
<div class="figure">Figure: Solid brush</div>


<h2>Hatch brushes</h2>

<p>
There are six predefined hatch brushes available. In our example, we
show all of them.
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawRectangles(HWND hwnd);


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_VREDRAW | CS_HREDRAW;
  wc.lpszClassName = L"Brush";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Hatch brushes",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 300, 220, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_PAINT:

      DrawRectangles(hwnd);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

void DrawRectangles(HWND hwnd)
{
  PAINTSTRUCT ps;

  HDC hdc = BeginPaint(hwnd, &amp;ps);
  HPEN hPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
  HPEN holdPen = SelectObject(hdc, hPen);

  HBRUSH hBrush1 = CreateHatchBrush(HS_BDIAGONAL, RGB(0, 0, 0));
  HBRUSH hBrush2 = CreateHatchBrush(HS_FDIAGONAL, RGB(0, 0, 0));
  HBRUSH hBrush3 = CreateHatchBrush(HS_CROSS, RGB(0, 0, 0));
  HBRUSH hBrush4 = CreateHatchBrush(HS_HORIZONTAL, RGB(0, 0, 0));
  HBRUSH hBrush5 = CreateHatchBrush(HS_DIAGCROSS, RGB(0, 0, 0));
  HBRUSH hBrush6 = CreateHatchBrush(HS_VERTICAL, RGB(0, 0, 0));

  HBRUSH holdBrush = SelectObject(hdc, hBrush1);

  DWORD col = GetSysColor(COLOR_BTNFACE);
  SetBkColor(hdc, col);

  Rectangle(hdc, 30, 30, 100, 80);
  SelectObject(hdc, hBrush2);
  Rectangle(hdc, 110, 30, 180, 80);
  SelectObject(hdc, hBrush3);
  Rectangle(hdc, 190, 30, 260, 80);
  SelectObject(hdc, hBrush4);
  Rectangle(hdc, 30, 110, 100, 160);
  SelectObject(hdc, hBrush5);
  Rectangle(hdc, 110, 110, 180, 160);
  SelectObject(hdc, hBrush6);
  Rectangle(hdc, 190, 110, 260, 160);

  SelectObject(hdc, holdPen);
  SelectObject(hdc, holdBrush);

  DeleteObject(hPen);
  DeleteObject(hBrush1);
  DeleteObject(hBrush2);
  DeleteObject(hBrush3);
  DeleteObject(hBrush4);
  DeleteObject(hBrush5);
  DeleteObject(hBrush6);

  EndPaint(hwnd, &amp;ps);
}
</pre>

<p>
This example is very similar to the previous one. We only use a new
function call <code>CreateHatchBrush()</code>
</p>

<pre class="explanation">
HBRUSH hBrush1 = CreateHatchBrush(HS_BDIAGONAL, RGB(0, 0, 0));
</pre>

<p>
A diagonal hatch brush is created. 
</p>

<pre class="explanation">
HBRUSH holdBrush = SelectObject(hdc, hBrush1);
</pre>

<p>
The brush is selected into the device context. A handle to the old brush is
returned.  
</p>

<pre class="explanation">
DeleteObject(hBrush1);
</pre>

<p>
The brush object is deleted.
</p>


<img src="/img/gui/winapi/hatchbrush.png" alt="Hatch brush">
<div class="figure">Figure: Hatch brush</div>


<h2>Shapes</h2>

<p>
Shapes are more sophisticated geometrical objects. We will draw various
geometrical shapes in the following example.
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Shapes";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Shapes",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 390, 230, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
    WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  const POINT polygon[10] = { 30, 145, 85, 165, 105, 
      110, 65, 125, 30, 105 };
  const POINT bezier[4] = {280, 160, 320, 160, 
      325, 110, 350, 110};

  switch(msg)
  {
    case WM_PAINT:

      hdc = BeginPaint(hwnd, &amp;ps);

      Ellipse(hdc, 30, 30, 120, 90);
      RoundRect(hdc, 150, 30, 240, 90, 15, 20);
      Chord(hdc, 270, 30, 360, 90, 270, 45, 360, 45);
      Polygon(hdc, polygon, 5);
      Rectangle(hdc, 150, 110, 230, 160);
      PolyBezier(hdc, bezier, 4);

      EndPaint(hwnd, &amp;ps);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}
</pre>

<p>
In our example, we have created an ellipse, a rounded rectangle, 
a chord, a polygon, a rectangle and a bezier curve.
</p>

<pre class="explanation">
Ellipse(hdc, 30, 30, 120, 90);
</pre>

<p>
The <code>Ellipse()</code> function draws an ellipse. The parameters of the
function are the x, y coordinates of the upper-left and bottom-right of corner 
a bounding rectangle. The ellipse is drawn within this rectangle.
</p>

<pre class="explanation">
RoundRect(hdc, 150, 30, 240, 90, 15, 20);
</pre>

<p>
The <code>RoundRect()</code> function draws a rectangle with rounded corners.
</p>

<pre class="explanation">
Chord(hdc, 270, 30, 360, 90, 270, 45, 360, 45);
</pre>

<p>
The <code>Chord()</code> function draws a chord. 
</p>

<pre class="explanation">
Polygon(hdc, polygon, 5);
</pre>

<p>
The <code>Polygon()</code> function draws a polygon consisting of two or more 
vertices connected by straight lines. The polygon is a pointer to an array of 
POINT structures that specify the vertices of the polygon. The last parameter
is the number of points in the array.
</p>

<pre class="explanation">
Rectangle(hdc, 150, 110, 230, 160);
</pre>

<p>
The <code>Rectangle()</code> function draws a rectangle. The parameters
of the function are the x, y coordinates of the upper-left and lower-right
corner of the rectangle.
</p>

<pre class="explanation">
PolyBezier(hdc, bezier, 4);
</pre>

<p>
The <code>PolyBezier()</code> function draws one or more Bézier curves.
The second parameter is a pointer to an array of POINT structures that 
contains the endpoints and control points of the curve. The third parameter is 
the number of points in the array.
</p>


<img src="/img/gui/winapi/shapes.png" alt="Shapes">
<div class="figure">Figure: Shapes</div>


<h2>Text</h2>

<p>
The <code>TextOutW()</code> function writes a character string at the specified 
location, using the currently selected font, background colour, and text colour.
</p>

<pre class="code">
#include &lt;windows.h&gt;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PWSTR lpCmdLine, int nCmdShow)
{
  MSG  msg ;
  WNDCLASSW wc = {0};

  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpszClassName = L"Sonnet 55";
  wc.hInstance     = hInstance;
  wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(0, IDC_ARROW);

  RegisterClassW(&amp;wc);
  CreateWindowW(wc.lpszClassName, L"Sonnet 55",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 390, 350, NULL, NULL, hInstance, NULL);

  while( GetMessage(&amp;msg, NULL, 0, 0)) {
      DispatchMessage(&amp;msg);
  }

  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
  WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;

  DWORD color;

  HFONT hFont, holdFont;

  static wchar_t *ver1 = L"Not marble, nor the gilded monuments";
  static wchar_t *ver2 = L"Of princes, shall outlive this powerful rhyme;";
  static wchar_t *ver3 = L"But you shall shine more bright in these contents";
  static wchar_t *ver4 = L"Than unswept stone, besmear'd with sluttish time.";
  static wchar_t *ver5 = L"When wasteful war shall statues overturn,";
  static wchar_t *ver6 = L"And broils root out the work of masonry,";
  static wchar_t *ver7 = L"Nor Mars his sword, nor war's quick fire shall burn";
  static wchar_t *ver8 = L"The living record of your memory.";
  static wchar_t *ver9 = L"'Gainst death, and all oblivious enmity";
  static wchar_t *ver10 = L"Shall you pace forth; your praise shall still find room";
  static wchar_t *ver11 = L"Even in the eyes of all posterity";
  static wchar_t *ver12 = L"That wear this world out to the ending doom.";
  static wchar_t *ver13 = L"So, till the judgment that yourself arise,";
  static wchar_t *ver14 = L"You live in this, and dwell in lovers' eyes.";

  switch(msg)
  {
    case WM_PAINT:

      hdc = BeginPaint(hwnd, &ps);

      color = GetSysColor(COLOR_BTNFACE);
      SetBkColor(hdc, color);

      hFont = CreateFontW(15, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0,
          0, 0, 0, 0, L"Georgia");
      holdFont = SelectObject(hdc, hFont);

      TextOutW(hdc, 50, 20,  ver1,  lstrlenW(ver1));
      TextOutW(hdc, 50, 40,  ver2,  lstrlenW(ver2));
      TextOutW(hdc, 50, 60,  ver3,  lstrlenW(ver3));
      TextOutW(hdc, 50, 80,  ver4,  lstrlenW(ver4));
      TextOutW(hdc, 50, 100, ver5,  lstrlenW(ver5));
      TextOutW(hdc, 50, 120, ver6,  lstrlenW(ver6));
      TextOutW(hdc, 50, 140, ver7,  lstrlenW(ver7));
      TextOutW(hdc, 50, 160, ver8,  lstrlenW(ver8));
      TextOutW(hdc, 50, 180, ver9,  lstrlenW(ver9));
      TextOutW(hdc, 50, 200, ver10, lstrlenW(ver10));
      TextOutW(hdc, 50, 220, ver11, lstrlenW(ver11));
      TextOutW(hdc, 50, 240, ver12, lstrlenW(ver12));
      TextOutW(hdc, 50, 260, ver13, lstrlenW(ver13));
      TextOutW(hdc, 50, 280, ver14, lstrlenW(ver14));

      SelectObject(hdc, holdFont);
      DeleteObject(hFont);

      EndPaint(hwnd, &ps);
      break;

    case WM_DESTROY:

      PostQuitMessage(0);
      return 0;
  }

  return DefWindowProcW(hwnd, msg, wParam, lParam);
}
</pre>

<p>
We draw a few verses on the window with the <code>TextOutW()</code> function.
</p>

<pre class="explanation">
color = GetSysColor(COLOR_BTNFACE);
SetBkColor(hdc, color);
</pre>

<p>
By default, if we draw some text on the client area of the window, the
background is set to white color. We can change this by setting the
background color using the <code>SetBkColor()</code> function. We used the
typical Windows gray color. The <code>GetSysColor()</code> function is used
to get the system colors used in buttons, title or backround of window controls.
</p>

<pre class="explanation">
hFont = CreateFontW(15, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0,
    0, 0, 0, 0, L"Georgia");
holdFont = SelectObject(hdc, hFont);
</pre>

<p>
Here we create a font object. There are 14 parameters. We don't have
to specify all of them. We used only the font size, font weight and
fontface parameters.
</p>

<pre class="explanation">
TextOutW(hdc, 50, 20, verse1, lstrlenW(verse1));
</pre>

<p>
The text is drawn onto the window using the <code>TextOutW()</code>
function.
</p>

<img src="/img/gui/winapi/sonnet55.png" alt="Text">
<div class="figure">Figure: Text</div>

<p>
In this part of the Winapi tutorial, we did some drawing.
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br>

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified October 1, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
